﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Mono.Cecil;
using Mono.Cecil.Cil;
using TK_CSLua.ILAnalyze;

namespace CSLua
{
	// Token: 0x02000025 RID: 37
	public abstract class TypeGenerator : BuildFilePhase
	{
		// Token: 0x0600016D RID: 365 RVA: 0x0000A007 File Offset: 0x00008207
		public TypeGenerator(LuaType luaType, CodeWriter builder) : base(luaType, builder)
		{
			this.luaType = luaType;
		}

		// Token: 0x0600016E RID: 366
		protected abstract string FileSuffix();

		// Token: 0x0600016F RID: 367
		protected abstract string Export(string typeDefineName);

		// Token: 0x06000170 RID: 368 RVA: 0x0000A018 File Offset: 0x00008218
		protected virtual void SpellOutCode(StringBuilder typeSrcBuilder)
		{
			BuildFileContext ctx = this.buildContext;
			string typeDefineName = ctx.getTypeDefineName(this.luaType.ILTypeDef);
			typeSrcBuilder.Append(this.buildHeaderCode());
			typeSrcBuilder.Append(this.writer.src());
			typeSrcBuilder.Append(ctx.buildTailCode());
			typeSrcBuilder.Append(this.generateStaticInit());
			typeSrcBuilder.AppendFormat(this.Export(typeDefineName), new object[0]);
		}

		// Token: 0x06000171 RID: 369
		public abstract string buildHeaderCode();

		// Token: 0x06000172 RID: 370 RVA: 0x0000A08C File Offset: 0x0000828C
		public void Generate(string outFolderRoot)
		{
			this.generateTypes();
			string errorMsg = this.writer.errors();
			if (!string.IsNullOrEmpty(errorMsg))
			{
				BuilderUtils.ErrorLine(errorMsg);
			}
			StringBuilder typeSrcBuilder = new StringBuilder();
			string typeDefineName = this.buildContext.getTypeDefineName(this.luaType.ILTypeDef);
			this.SpellOutCode(typeSrcBuilder);
			string src = typeSrcBuilder.ToString();
			if (string.IsNullOrEmpty(outFolderRoot))
			{
				outFolderRoot = ".";
			}
			FileInfo info = new FileInfo(Path.Combine(outFolderRoot, this.luaType.LuaModule, typeDefineName + this.FileSuffix()));
			if (!info.Directory.Exists)
			{
				info.Directory.Create();
			}
			if (!string.IsNullOrEmpty(BuildConfig.moveFolder))
			{
				FileInfo moveFormFile = new FileInfo(Path.Combine(BuildConfig.moveFolder, this.luaType.LuaModule, typeDefineName + this.FileSuffix()));
				if (moveFormFile.Exists)
				{
					File.Move(moveFormFile.FullName, info.FullName);
					FileInfo moveFormMetaFile = new FileInfo(moveFormFile.FullName + ".meta");
					if (moveFormMetaFile.Exists)
					{
						File.Move(moveFormMetaFile.FullName, info.FullName + ".meta");
					}
					Console.WriteLine("move:" + info.FullName);
				}
			}
			if (info.Exists && File.ReadAllText(info.FullName) == src)
			{
				return;
			}
			File.WriteAllText(info.FullName, src);
			BuilderUtils.DebugLine("------translate------>" + info.FullName);
		}

		// Token: 0x06000173 RID: 371 RVA: 0x0000A21C File Offset: 0x0000841C
		private void generateNestClassDeclare()
		{
			this.writer.commentLine("-------------------");
			foreach (LuaType type in this.luaType.NestedLuaTypes)
			{
				this.writer.defineLocalValue(this.buildContext.getTypeDefineName(type.ILTypeDef), null);
			}
			this.writer.commentLine("-------------------");
		}

		// Token: 0x06000174 RID: 372
		protected abstract void generateClassDefine(LuaType clazz, bool defined = false);

		// Token: 0x06000175 RID: 373 RVA: 0x0000A2A8 File Offset: 0x000084A8
		protected bool isNeedExtends(TypeDefinition type)
		{
			return type.BaseType != null && !type.BaseType.isTypeOf<object>() && !type.BaseType.isTypeOf<ValueType>() && !type.BaseType.isDelegate() && this.buildContext.isLuaType(type.BaseType);
		}

		// Token: 0x06000176 RID: 374 RVA: 0x0000A2F7 File Offset: 0x000084F7
		private void generateTypes()
		{
			this.generateNestClassDeclare();
			this.generateClassDefine(this.luaType, false);
			this.tryGenerateBehaviourBind();
			this.tryGenerateModelClone(this.luaType);
			this.generateMethods(this.luaType);
			this.generateNestClassBody();
		}

		// Token: 0x06000177 RID: 375
		protected abstract string generateStaticInit();

		// Token: 0x06000178 RID: 376 RVA: 0x0000A334 File Offset: 0x00008534
		private void generateNestClassBody()
		{
			foreach (LuaType nestedType in this.luaType.NestedLuaTypes)
			{
				this.generateNestClassBodyImpl(nestedType);
				this.tryGenerateModelClone(nestedType);
			}
			foreach (LuaType nestedType2 in this.luaType.NestedLuaTypes)
			{
				this.generateAssignNestdClass(nestedType2);
			}
		}

		// Token: 0x06000179 RID: 377 RVA: 0x0000A3D0 File Offset: 0x000085D0
		private void generateNestClassBodyImpl(LuaType nestdType)
		{
			this.generateClassDefine(nestdType, true);
			this.generateMethods(nestdType);
		}

		// Token: 0x0600017A RID: 378
		protected abstract void generateAssignNestdClass(LuaType clazz);

		// Token: 0x0600017B RID: 379 RVA: 0x0000A3E4 File Offset: 0x000085E4
		protected virtual void generateMethods(LuaType luaType)
		{
			TypeDefinition type = luaType.ILTypeDef;
			using (IEnumerator<LuaMethod> enumerator = luaType.LuaMethods.GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					LuaMethod luaMethod = enumerator.Current;
					MethodDefinition method = luaMethod.method;
					this.writer.nextLine();
					this.writer.commentLine("");
					
					this.writer.commentLine("ILMethod:" + method);
					string methodName = this.buildContext.getMethodName(method);
					if (method.isStaticCtor())
					{
						methodName = BuildConfig.static_initialize_func;
					}
					if (BuildConfig.commontMethodVar)
					{
						foreach (VariableDefinition var in method.Body.Variables)
						{
							this.writer.commentLine(string.Concat(var));
						}
					}
					bool isStatic = method.IsStatic;
					this.writer.beginDefineMethod(this.buildContext.getTypeDefineName(type), method.IsStatic, methodName, delegate
					{
						this.writer.dot<string>(luaMethod.Args, delegate(string arg, int index)
						{
							this.writer.code(arg);
						});
					}).shiftRightNewLine();
					if (method.isCtor())
					{
						this.generateCtorFieldInit(type);
					}
					method.isStaticCtor();
					if (method.hasAttributes(BuildConfig.ScriptImplAttribute))
					{
						this.writer.code(method.getAttribute(BuildConfig.ScriptImplAttribute).ConstructorArguments.First<CustomAttributeArgument>().Value.ToString());
					}
					else
					{
						try
						{
							this.CreateMethodGenerator(luaMethod).GenerateBody();
						}
						catch (Exception ex)
						{
							Console.Write("生成函数：" + luaMethod.ILMethod.FullName + "时候错误！");
							throw ex;
						}
					}
					this.writer.shiftLeftNewLine(delegate()
					{
						this.writer.endDefineMethod();
					});
				}
			}
			if (!luaType.HasCtor)
			{
				this.GenerateCtor(luaType);
			}
		}

		// Token: 0x0600017C RID: 380
		protected abstract void GenerateCtor(LuaType luaType);

		// Token: 0x0600017D RID: 381
		protected abstract MethodGenerator CreateMethodGenerator(LuaMethod luaMethod);

		// Token: 0x0600017E RID: 382
		protected abstract void generateCtorFieldInit(TypeDefinition type);

		// Token: 0x0600017F RID: 383 RVA: 0x0000A620 File Offset: 0x00008820
		private void buildStaticMemberFieldInit(TypeDefinition type)
		{
			foreach (FieldDefinition field in type.Fields)
			{
				if (field.IsStatic && !field.HasDefault && field.FieldType.IsValueType)
				{
					this.writer.codeFormat("{0}.{1} = {2}", new object[]
					{
						this.buildContext.getTypeId(type, false),
						field.luaIdentifier(),
						this.buildContext.defaultValueCode(field.FieldType)
					}).nextLine();
				}
			}
		}

		// Token: 0x06000180 RID: 384
		protected abstract bool tryGenerateModelClone(LuaType luaType);

		// Token: 0x06000181 RID: 385
		protected abstract bool tryGenerateBehaviourBind();

		// Token: 0x0400009B RID: 155
		private new LuaType luaType;
	}
}
